<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Constants\StatusConstants;
use App\Common\Robot\Robot;
use App\CustHub\Event\RobotInfoChange;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChSeatMapper;
use App\CustHub\Mapper\ChServerMapper;
use App\CustHub\Model\ChCorp;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChRobotLoginLog;
use App\Robot\Service\RobotApiService;
use Carbon\Carbon;
use FriendsOfHyperf\Lock\Exception\LockTimeoutException;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\MineCollection;
use Mine\MineModel;
use Mine\MineResponse;
use Psr\Http\Message\ResponseInterface;
use function FriendsOfHyperf\Lock\lock;
use function Hyperf\Coroutine\co;
use function Yansongda\Supports\data_get;

class ChRobotService extends AbstractService
{
    public  $mapper;

    #[Inject]
    protected ChSeatMapper $seatMapper;

    #[Inject]
    protected ChServerService $serverService;

    public function __construct(ChRobotMapper $mapper)
    {
        $this->mapper = $mapper;
        //总后台需要维护机器人服务器列表
        //用户购买席位后自动匹配机器人最少得服务器到当前席位
        //当前用户扫码登录的时候 根据用户所在地区 查询最近的服务器然后变更席位对应的服务器地址
    }

    public function getRobotApiService(mixed $robotId,bool $isNeedLogin = false): RobotApiService|false
    {
        $robotInfo = $this->mapper->findById($robotId);
        if($isNeedLogin && $robotInfo['login_status'] != 1){
           return false;
        }
        return make(RobotApiService::class, [$robotInfo['server_id'], $robotInfo['robot_key']]);
    }

    /**
     * 机器人列表
     * @param array $params
     * @return array
     */
    public function list(array $params): array
    {
        $pageSize = $params['page_size'] ?? MineModel::PAGE_SIZE;
        $query = ChRobot::query()
            ->select(['id','uid','main_uid','nickname','alias','remark','avatar','corp_id','corp_name','user_id','contact_num','room_num','login_status','is_auto_renewal','pro_code','city_code','ht_bind_status'])
            ->withPermission((int) $params['uid'])
            ->with(['groups'=>function ($query) {
                $query->select(['id','name']);
            },'user'=>function ($query) {
                $query->select(['id','username as nickname']);
            }]);
        $p =  $this->mapper->handleSearch($query, $params)
            ->orderBy('created_at','desc')
            ->paginate((int)$pageSize);

       $p->getCollection()->transform(function ($item){
           $item->nickname = !empty($item->alias) ? $item->nickname . "（{$item->alias}）" : $item->nickname;
           $item->is_main = $item->main_uid == $item->uid ? 1 : 0;
           return $item;
        });


        return $this->mapper->setPaginate($p);
    }

    /**
     * 删除机器人
     * @param mixed $id
     * @return bool|int|mixed|null
     * @throws \Exception
     */
    #[Transaction]
    public function deleteById(mixed $id): mixed
    {
        $robotInfo = $this->mapper->findById($id);
        if(empty($robotInfo)){
            return false;
        }
        if($robotInfo->login_status == 1){
            $robotApiService = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();
            $rst = $robotApiService->loginOut();
            if($rst === false){
                return false;
            }


        }
        
        if(!empty($robotInfo->seat_id)){
            //更新席位使用状态
            $this->seatMapper->update($robotInfo->seat_id,[
                'use_status' => StatusConstants::DISABLE
            ]);
        }
        //更新机器人状态
        $this->mapper->update($robotInfo->id,[
            'login_status' => 0,
            'login_out_time' => Carbon::now()->toDateTimeString(),
            'seat_id' => 0
        ]);
        $this->mapper->clearCache($robotInfo['id'],$robotInfo->uuid);

        $this->serverService->decrement($robotInfo->server_id);
        return $robotInfo->delete();
    }


    public function checkLogin(array $data): int
    {
        $robotInfo = $this->mapper->findById($data['id']);
        $status = 0;
        if(empty($robotInfo)){
            return $status;
        }
        $key = "robot_login_success:".$robotInfo->user_id;
        $info =  redis()->get($key);
        if(!empty($info)){
            $status = 1;
            redis()->del($key);
        }
        return $status;
    }


    public function getLabelList(array $params)
    {
        $robotInfo = $this->mapper->findById($params['robot_id']);
        if(empty($robotInfo)){
            throw new NormalStatusException('请选择企微号');
        }
        $service = make(Robot::class, [$robotInfo->server_id, $robotInfo->robot_key])->gateway();
        $response = $service->getTagList(1);
        return $response;
    }

    public function getRobotSelectList(array $params)
    {
        $keyword = data_get($params, 'keyword', '');
        $corpId = data_get($params,'corp_id');
        $pageSize = data_get($params, 'page_size', 10);

        $paginate = ChRobot::query()
            ->withPermission((int)$params['uid'])
            ->when(!empty($keyword),function ($query) use ($keyword){
                $query->where('nickname','like','%'.$keyword.'%');
            })->when(!empty($corpId),function ($query) use ($corpId){
                $query->where('corp_id',$corpId);
            })->paginate((int)$pageSize);

        return $this->mapper->setPaginate($paginate);
    }

    /**
     * 根据uid获取机器人列表
     * @param mixed $uid
     * @return array
     */
    public function getRobotListByUid(mixed $uid): array
    {
        return ChRobot::query()
            ->select(['id','nickname','avatar','user_id','login_status'])
            ->withPermission((int)$uid)
            ->get()->toArray();
    }

    public function loginRecord(array $params)
    {
        $pageSize = data_get($params, 'page_size', MineModel::PAGE_SIZE);

        $paginate = ChRobotLoginLog::query()
            ->select(['id','type','remark','created_at'])
            ->where('robot_id',$params['id'])
            ->orderBy('created_at','desc')
            ->paginate((int)$pageSize);

        return $this->mapper->setPaginate($paginate);
    }

    /**
     * 根据机器人ids查询
     * @param mixed $uid
     * @return array
     */
    public function getRobotListByIds(array $ids): array
    {
        return ChRobot::query()
            ->select(['id','nickname','avatar','user_id','login_status','corp_name'])
            ->whereIn('id',$ids)
            ->get()->toArray();
    }


    /**
     * 判断用户是否为企微用户
     * @param mixed $uid
     */
    public function isSystemSender($sender): bool
    {
        $count = ChRobot::query()
            ->where('user_id',$sender)
            ->count();
        return $count>0;
    }

    public function export(array $params, ?string $dto, ?string $filename = null, ?\Closure $callbackData = null): ResponseInterface
    {
        if (empty($dto)) {
            return container()->get(MineResponse::class)->error('导出未指定DTO');
        }

        if (empty($filename)) {
            $filename = "企微号列表".Carbon::now()->toDateTimeString();
        }

        $query = ChRobot::query()
            ->withPermission((int) $params['uid'])
            ->with(['groups'=>function ($query) {
                $query->select(['id','name']);
            },'user'=>function ($query) {
                $query->select(['id','nickname','parent_id']);
            }]);
        $list =  $this->mapper->handleSearch($query, $params)
            ->orderBy('created_at','desc')
            ->get();

        $list->transform(function ($item){
            $item->login_status_text = $item->login_status == 1 ? '已登录' : '未登录';
            $item->group_name = !empty($item->groups) ? $item->groups->pluck('name')->implode(',') : '';
            $item->user_name = '';
            if(!empty($item->user)){
                if($item->user->parent_id == 0){
                    $item->user_name = '主账号';
                }else{
                    $item->user_name = $item->user->username;
                }
            }
            return $item;
        });

        return (new MineCollection())->export($dto, $filename, $list->toArray(), $callbackData);
    }

    public function getPersonalQRCode(array $params)
    {
        $key = "get_robot_qrcode:".$params['id'];

        $qrCode = redis()->get($key);
        if($qrCode){
            return $qrCode;
        }

        $robot = $this->mapper->findById($params['id']);
        if(empty($robot)){
            throw new NormalStatusException('请选择企微号');
        }

        if(!$robot->login_status){
            throw new NormalStatusException('请先登录企微号');
        }

        $service = make(Robot::class, [$robot->server_id, $robot->uuid])->gateway();

        $result = $service->getPersonalQRCode();
        if($result === false){
            throw new NormalStatusException('获取失败');
        }

        $qrCode = $result['qrcode_url'];
        redis()->set($key,$qrCode,6 * 86400);
        return $qrCode;
    }

    /**
     * 修改备注
     * @param array $data
     * @return bool
     */
    public function editRemark(array $data): bool
    {
        $robot = $this->mapper->findById($data['id']);
        if(empty($robot)){
            throw new NormalStatusException('请选择企微号');
        }

        $robot->remark = $data['remark'];
        return $robot->save();
    }

    public function resetClient(array $params): bool
    {
        $robot = $this->mapper->findById($params['id']);
        if(empty($robot)){
            throw new NormalStatusException('请选择企微号');
        }

        if($robot['login_status'] == 1){
            throw new NormalStatusException('请下线后进行重置操作');
        }

        $rst = $this->mapper->update($robot->id,[
            'uuid' => ""
        ]);
        $this->mapper->clearCache($params['id']);
        return $rst;
    }

    public function getRobotList(array $params): array
    {
        $id = data_get($params,'id');
        $robot = $this->mapper->findById($id);
        if(empty($robot)){
            throw new NormalStatusException('请选择企微号');
        }
        $nickname = \Hyperf\Collection\data_get($params,'nickname');
        $bindStatus = \Hyperf\Collection\data_get($params,'bind_status');
        $pageSize = data_get($params, 'page_size', MineModel::PAGE_SIZE);

        $robotList = ChRobot::query()
            ->select(['id','nickname','ht_bind_status'])
            ->withPermission((int) $params['uid'])
            ->where('corp_id',$robot->corp_id)
            ->when(!empty($nickname),function ($query) use ($nickname){
                $query->where('nickname','like',"%{$nickname}%");
            })
            ->when(filled($bindStatus),function ($query) use ($bindStatus){
                $query->where('ht_bind_status',$bindStatus);
            })
            ->orderBy('created_at','desc')
            ->paginate((int)$pageSize);

        return $this->mapper->setPaginate($robotList);
    }

    public function updateRobot(array $params): void
    {
        $mainUid = $params['main_uid'];

        $lock = lock('batch_update_robot_'.$mainUid,6);
        try {
            $lock->block(4);
            co(function () use ($mainUid){
                ChRobot::query()
                    ->where('main_uid',$mainUid)
                    ->where('login_status',1)
                    ->chunk(100,function ($list){
                        foreach ($list as $item){
                            event(new RobotInfoChange($item));
                            Coroutine::sleep(rand(2,3));
                        }
                        Coroutine::sleep(rand(2,3));
                    });
            });
        } catch (LockTimeoutException $e) {
            throw new NormalStatusException('更新中，请稍后刷新页面查看结果~');
        } finally {
            $lock->release();
        }
    }

    /**
     * 获取机器人服务商主体下的密文userid
     * @param $robotId
     * @return string
     */
    public function getOpenid($robotId): string
    {
        $robot = $this->mapper->findById($robotId);
        if (empty($robot) || $robot->login_status != 1){
            return '';
        }
        $apiService = make(Robot::class, [$robot->server_id, $robot->uuid])->gateway();
        $response = $apiService->getProfile();
        if($response !== false){
            $acctid = $response['acctid'] ?? '';
            if(empty($acctid)){
                logger()->info('获取服务商用户acctid失败'.json_encode($response));
                return '';
            }
            $corpInfo = ChCorp::query()
                ->where('id',$robot->corp_id)
                ->first();
            if($corpInfo->auth_status != 1){
                logger()->info('获取服务商用户openid失败-企业未授权');
                return '';
            }
            try {
                $response = make(OpenWorkService::class,[$corpInfo->auth_corp_id])->getOpenUserid([$acctid]);
                if(!empty($response['open_userid_list'])){
                    $openUserId = $response['open_userid_list'][0]['open_userid'];
                    $this->mapper->update($robotId,[
                        'acctid' => $acctid,
                        'userid' => $openUserId
                    ]);
                    $this->mapper->clearCache($robotId);
                    return $openUserId;
                }else{
                    logger()->info('获取服务商用户openid失败-获取失败'.$response['errmsg']);
                    return '';
                }
            }catch (\Throwable $e){
                logger()->info('获取服务商用户openid失败-获取失败'.$e->getMessage());
                return '';
            }
        }
        return '';
    }
}